package com.spring.flowable.domain;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.spring.flowable.util.TypeEnum;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @author liuzhiqiang
 */
public class BpmnDomain {

    /**
     * bpmnModel 对象
     */
    private BpmnModel bpmnModel;

    /**
     * 过程对象
     */
    private Process process;

    /**
     * 所有连线
     */
    private List<SequenceFlow> sequenceFlows;

    /**
     * 节点数据
     */
    private ProcessNode processNode;

    /**
     * 开始节点
     */
    private StartEvent startEvent;

    /**
     * 结束节点
     */
    private EndEvent endEvent;


    public static BpmnDomain builder() {
        BpmnDomain bpmnDomain = new BpmnDomain();

        BpmnModel bpmnModel = new BpmnModel();
        Process process = new Process();
        bpmnModel.addProcess(process);

        StartEvent startEvent = new StartEvent();
        startEvent.setId("START_" + IdUtil.getSnowflakeNextIdStr());
        startEvent.setName("开始");
        process.addFlowElement(startEvent);

        EndEvent endEvent = new EndEvent();
        startEvent.setId("END_" + IdUtil.getSnowflakeNextIdStr());
        startEvent.setName("结束");
        List<SequenceFlow> sequenceFlows = new ArrayList<>();

        bpmnDomain.bpmnModel = bpmnModel;
        bpmnDomain.process = process;
        bpmnDomain.startEvent = startEvent;
        bpmnDomain.endEvent = endEvent;
        bpmnDomain.sequenceFlows = sequenceFlows;
        return bpmnDomain;
    }

    public BpmnDomain processId(String id) {
        this.process.setId(id);
        return this;
    }

    public BpmnDomain processName(String name) {
        this.process.setName(name);
        return this;
    }

    public BpmnDomain processExtension(String name, String value) {
        ExtensionAttribute extensionAttribute = new ExtensionAttribute();
        extensionAttribute.setName(name);
        extensionAttribute.setValue(value);
        this.process.addAttribute(extensionAttribute);
        return this;
    }

    public BpmnDomain bindProcessNode(ProcessNode processNode) {
        this.processNode = processNode;
        return this;
    }

    public BpmnDomain generate() {
        if (this.processNode != null) {
            this.createBpmn(this.startEvent, this.processNode);
            return this;
        } else {
            return null;
        }
    }

    private void createBpmn(FlowNode currentNode, ProcessNode processNode) {

        if (StrUtil.equals(processNode.getType(), TypeEnum.ROOT.getType())) {
            // 发起人节点
            this.createRoot(currentNode, processNode);
        } else if (StrUtil.equals(processNode.getType(), TypeEnum.APPROVAL.getType())) {
            // 审批人节点
            this.createApproval(currentNode, processNode);
        }


    }

    /**
     * 审批人节点
     *
     * @param currentNode
     * @param processNode
     */
    private void createApproval(FlowNode currentNode, ProcessNode processNode) {
        UserTask userTask = new UserTask();
        userTask.setName(processNode.getName());
        userTask.setId(processNode.getId());

        Assignee assignee = processNode.getAssignee();
        MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = new MultiInstanceLoopCharacteristics();

        // 审批人集合参数
        multiInstanceLoopCharacteristics.setInputDataItem(userTask.getId() + "assigneeList");
        // 迭代集合
        multiInstanceLoopCharacteristics.setElementVariable("assigneeName");

        // 并行
        if (assignee.getSequential() != null) {
            multiInstanceLoopCharacteristics.setSequential(assignee.getSequential());
        } else {
            multiInstanceLoopCharacteristics.setSequential(false);
        }

        userTask.setAssignee("${assigneeName}");
        // 设置多实例属性
        userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);



    }

    /**
     * 发起人节点
     *
     * @param currentNode
     * @param processNode
     * @return
     */
    private void createRoot(FlowNode currentNode, ProcessNode processNode) {
        UserTask userTask = new UserTask();
        userTask.setName(processNode.getName());
        userTask.setId(processNode.getId());
        this.process.addFlowElement(userTask);
        SequenceFlow sequenceFlow = createSequenceFlow(currentNode.getId(), userTask.getId());
        this.process.addFlowElement(sequenceFlow);
        ProcessNode nextProcessNode = processNode.getNext();
        if (nextProcessNode != null) {
            createBpmn(userTask, nextProcessNode);
        }
    }


    /**
     * 创建连线
     *
     * @param from 来源节点id
     * @param to   目标节点id
     * @return
     */
    private SequenceFlow createSequenceFlow(String from, String to) {
        SequenceFlow flow = new SequenceFlow();
        flow.setId("SEQUENCE_FLOW_" + IdUtil.getSnowflakeNextIdStr());
        flow.setSourceRef(from);
        flow.setTargetRef(to);
        this.sequenceFlows.add(flow);
        return flow;
    }


}
